package dao

import (
	"errors"
	"fmt"
	"log"
	"time"
	"yundian/internel/app/dao/memberdao"
	"yundian/internel/app/helper"
	"yundian/internel/app/helper/request"
	"yundian/internel/app/models/coupon"
	"yundian/internel/app/models/couponinfo"
	"yundian/internel/app/models/membermodel"
	"yundian/internel/app/models/orders"
	"yundian/internel/pkg/dingo"
	"yundian/internel/pkg/dingo/global"
)

type CouponDao struct {
}

func NewCouponDao() *CouponDao {
	return &CouponDao{}
}

func (d *CouponDao) GetWxChargeCouponList(param *request.GetWxUseChargeCouponListReq) *dingo.ErrorWrap {
	var lst []*request.GetWxUseChargeCouponListRes
	nowTime := time.Now().Unix()

	// 字段
	fields := `ci.id,ci.type,ci.discounts,ci.threshold,IF(ci.name='','优惠券',ci.name)name,ci.end_time`
	db := global.Orm.Table("coupon_info ci").Select(fields)
	db.Where("(ci.device_sn=? OR ci.device_sn='') AND ci.open_id=?", param.DeviceSn, param.Openid)
	db.Where("status=? AND start_time<=? AND (end_time>? OR end_time=0)", 1, nowTime, nowTime)
	db.Find(&lst)

	return dingo.ErrorIf(db.Error, lst)
}

// 自动领取指定设备优惠券
func (d *CouponDao) WxAutoReceiveCoupon(param *request.GetWxReceiveCouponListReq) *dingo.ErrorWrap {
	param.Status = helper.TypeNumOrderCouponRecordStatusNotUse
	memberCouponData := d.GetWxReceiveCouponList(param)
	memberCouponList := memberCouponData.Unwrap().([]*request.GetWxReceiveCouponListRes)
	if len(memberCouponList) > 0 || memberCouponData.Err != nil {
		return dingo.ErrorIf(memberCouponData.Err)
	}

	param.Status = helper.TypeNumOrderCouponRecordStatusNotGrant
	receiveCouponData := d.GetWxReceiveCouponList(param)
	receiveCouponList := receiveCouponData.Unwrap().([]*request.GetWxReceiveCouponListRes)
	if len(receiveCouponList) == 0 || receiveCouponData.Err != nil {
		return dingo.ErrorIf(receiveCouponData.Err)
	}

	couponRecordId := receiveCouponList[0].Id
	if data := d.WxReceiveCoupon(&request.WxReceiveCouponReq{MemberId: param.MemberId, CouponRecordId: couponRecordId}); data.Err != nil {
		return dingo.ErrorIf(data.Err)
	}

	data := d.GrantOrderCouponInfoById(couponRecordId)
	return dingo.ErrorIf(data.Err)
}

// 领取优惠券
func (d *CouponDao) WxReceiveCoupon(param *request.WxReceiveCouponReq) *dingo.ErrorWrap {
	memberInfo := memberdao.NewMemberDao().GetMemberInfoById(param.MemberId).Unwrap().(*membermodel.MembersModel)
	if memberInfo.ID == 0 {
		return dingo.ErrorIf(errors.New("memberId is err"))
	}

	db := global.Orm.Table("order_coupon_record")
	db.Where("id=? AND status=?", param.CouponRecordId, helper.TypeNumOrderCouponRecordStatusNotGrant)
	db.Updates(map[string]interface{}{
		"member_id":    memberInfo.ID,
		"member_phone": memberInfo.Phone,
		"status":       helper.TypeNumOrderCouponRecordStatusNotUse,
	})

	return dingo.ErrorIf(db.Error)
}

func (d *CouponDao) GetWxReceiveCouponList(param *request.GetWxReceiveCouponListReq) *dingo.ErrorWrap {
	var lst []*request.GetWxReceiveCouponListRes
	db := global.Orm.Table("order_coupon_record ocr").Select("ocr.*,COUNT(1)num")
	db.Where("place_id=? AND device_sn=?", param.PlaceId, param.DeviceSn)
	db.Where("status=? AND start_time<=now() AND end_time>now()", param.Status)

	if param.Status == helper.TypeNumOrderCouponRecordStatusNotUse {
		db.Where("member_id=?", param.MemberId)
	}

	db.Group("coupon_id")
	db.Find(&lst)

	return dingo.ErrorIf(db.Error, lst)
}

// GrantOrderCouponDevice 优惠券-设备预发放
func (d *CouponDao) GrantOrderCouponDevice(param *request.GrantOrderCouponReq) *dingo.ErrorWrap {
	orderCouponInfo := &coupon.OrderCoupon{}

	if db := global.Orm.Where("id=?", param.CouponId).Find(&orderCouponInfo); db.Error != nil {
		return dingo.ErrorIf(db.Error)
	}
	if orderCouponInfo.Num == 0 || orderCouponInfo.Status != helper.TypeNumOrderCouponStatusNotUnderway {
		return dingo.ErrorIf(errors.New("coupon is invalid"))
	}

	orderCouponRecord := coupon.OrderCouponRecordDb{
		PlaceId:      orderCouponInfo.PlaceId,
		CouponId:     orderCouponInfo.Id,
		Discounts:    orderCouponInfo.Discounts,
		Threshold:    orderCouponInfo.Threshold,
		Type:         orderCouponInfo.Type,
		OrderType:    orderCouponInfo.OrderType,
		Status:       helper.TypeNumOrderCouponRecordStatusNotGrant,
		ProjectLabel: orderCouponInfo.ProjectLabel,
		DeviceSn:     param.DeviceSn,
		Name:         orderCouponInfo.Name,
		Message:      orderCouponInfo.Message,
		StartTime:    orderCouponInfo.StartTime,
		EndTime:      orderCouponInfo.EndTime,
	}

	if db := global.Orm.Create(&orderCouponRecord); db.Error != nil {
		return dingo.ErrorIf(db.Error)
	}

	db := global.Orm.Exec(`UPDATE order_coupon SET num=num-1,grant_num=grant_num+1 WHERE id=?`, param.CouponId)
	return dingo.ErrorIf(db.Error)
}

// GrantOrderCouponInfoById 优惠券-发放
func (d *CouponDao) GrantOrderCouponInfoById(orderCouponRecordId int) *dingo.ErrorWrap {
	sql := `INSERT INTO coupon_info (c_id,start_time,end_time,user_id,status,order_id,open_id,device_sn,order_coupon_record_id,
	discounts,threshold,trade_no,name,type,place_id)SELECT 0,UNIX_TIMESTAMP(start_time),UNIX_TIMESTAMP(end_time),0,1,'',m.xcx_openid,
	device_sn,ocr.id,discounts,threshold,'',ocr.name,ocr.type,ocr.place_id FROM order_coupon_record ocr LEFT JOIN members m ON 
	ocr.member_id=m.id WHERE ocr.order_type=1 AND ocr.id=?`

	db := global.Orm.Exec(sql, orderCouponRecordId)
	return dingo.ErrorIf(db.Error)
}

// GrantOrderCouponInfo 优惠券-发放
func (d *CouponDao) GrantOrderCouponInfo(param *request.GrantOrderCouponReq, targetTime string) *dingo.ErrorWrap {
	sql := `INSERT INTO coupon_info (c_id,start_time,end_time,user_id,status,order_id,open_id,device_sn,order_coupon_record_id,
	discounts,threshold,trade_no,name,type,place_id)SELECT 0,UNIX_TIMESTAMP(start_time),UNIX_TIMESTAMP(end_time),member_id,1,'',
	m.xcx_openid,device_sn,ocr.id,discounts,threshold,'',ocr.name,ocr.type,ocr.place_id FROM order_coupon_record ocr LEFT JOIN 
	members m ON ocr.member_id=m.id WHERE ocr.order_type=1 AND ocr.coupon_id=? AND create_time=? AND device_sn=?`

	if len(param.MemberIds) > 0 {
		db := global.Orm.Exec(sql+" AND member_id IN ?", param.CouponId, targetTime, param.DeviceSn, param.MemberIds)
		return dingo.ErrorIf(db.Error)
	}

	db := global.Orm.Exec(sql, param.CouponId, targetTime, param.DeviceSn)
	return dingo.ErrorIf(db.Error)
}

// GrantOrderCoupon 优惠券-发放
func (d *CouponDao) GrantOrderCoupon(param *request.GrantOrderCouponReq) *dingo.ErrorWrap {
	var memberCount int64 = 0
	orderCouponInfo := &coupon.OrderCoupon{}

	db := global.Orm.Table("members m").Select("COUNT(1) member_count").Where("m.phone>''")
	if param.IsAll != 1 {
		db.Where("m.id IN ?", param.MemberIds)
	}
	if db.Count(&memberCount); db.Error != nil || memberCount == 0 {
		return dingo.ErrorIf(db.Error)
	}

	if db = global.Orm.Where("id=?", param.CouponId).Find(&orderCouponInfo); db.Error != nil {
		return dingo.ErrorIf(db.Error)
	}
	if int64(orderCouponInfo.Num) < memberCount || orderCouponInfo.Status != helper.TypeNumOrderCouponStatusNotUnderway {
		return dingo.ErrorIf(errors.New("coupon is invalid"))
	}

	targetTime := time.Now().Format("2006-01-02 15:04:05")
	sql := fmt.Sprintf(`INSERT INTO order_coupon_record (member_id,place_id,coupon_id,discounts,deduction_amount,
	threshold,type,order_type,status,project_label,start_time,end_time,name,member_name,member_phone,create_time)SELECT m.id,
	oc.place_id,oc.id,oc.discounts,0,oc.threshold,oc.type,oc.order_type,2,oc.project_label,oc.start_time,oc.end_time,oc.name, 
	'',m.phone,'%s' FROM members m LEFT JOIN (SELECT* FROM order_coupon WHERE id=? AND num>=?)oc ON 1 WHERE m.id>0 AND m.phone>''`, targetTime)
	if param.IsAll == 1 {
		db = global.Orm.Exec(sql, param.CouponId, memberCount)
	} else {
		db = global.Orm.Exec(sql+" AND m.id IN ? ", param.CouponId, memberCount, param.MemberIds)
	}

	if db.Error != nil {
		return dingo.ErrorIf(db.Error)
	}

	// 充电优惠券兼容同步
	if orderCouponInfo.OrderType == 1 {
		d.GrantOrderCouponInfo(param, targetTime)
	}

	db = global.Orm.Exec(`UPDATE order_coupon SET num=num-?,grant_num=grant_num+? WHERE id=?`, memberCount, memberCount, param.CouponId)
	return dingo.ErrorIf(db.Error)
}

// 查询优惠券记录
func (d *CouponDao) GetOrderCouponRecord(param *request.GetOrderCouponRecordListReq) *dingo.ErrorWrap {
	var (
		lst    []*request.GetOrderCouponRecordListRes
		count  int64
		limit  int = param.PageSize
		offset int = param.PageSize * (param.PageNo - 1)
	)

	field := `ocr.id,member_id,ocr.place_id,coupon_id,ocr.discounts,ocr.deduction_amount,ocr.threshold,ocr.type,
	ocr.order_type,ocr.status,ocr.trade_no,ocr.project_label,ocr.message,ocr.name,ocr.member_phone,
	DATE_FORMAT(ocr.start_time,'%Y-%m-%d %T')start_time,DATE_FORMAT(ocr.end_time,'%Y-%m-%d %T')end_time,
	DATE_FORMAT(ocr.create_time,'%Y-%m-%d %T')create_time,DATE_FORMAT(ocr.update_time,'%Y-%m-%d %T')update_time`
	db := global.Orm.Table("order_coupon_record ocr").Select(field)

	if param.IsAdmin != helper.TypeNumIsAdminOperator {
		db.Joins("LEFT JOIN places p ON ocr.place_id=p.id")
		db.Where("p.user_id=?", param.LoginUserId)
	}

	if param.Status > 0 {
		db.Where("ocr.status=?", param.Status)
	}
	if param.PlaceId > 0 {
		db.Where("ocr.place_id=?", param.PlaceId)
	}
	if param.Name != "" {
		db.Where("oc.name LIKE ?", "%"+param.Name+"%")
	}

	db.Order("ocr.id desc")
	db.Limit(limit).Offset(offset).Find(&lst).Limit(-1).Offset(-1).Count(&count)

	return dingo.ErrorIf(db.Error, lst, count)
}

// 优惠券
func (d *CouponDao) DeleteOrderCoupon(param *request.DbOrderCouponReq) *dingo.ErrorWrap {
	var count int64
	global.Orm.Model(&coupon.OrderCouponRecord{}).Where("coupon_id=?", param.DB.Id).Count(&count)
	if count > 0 {
		return dingo.ErrorIf(nil, count)
	}

	db := global.Orm.Delete(&param.DB)
	return dingo.ErrorIf(db.Error, count)
}

// 优惠券
func (d *CouponDao) UpdateOrderCoupon(param *request.DbOrderCouponReq) *dingo.ErrorWrap {
	db := global.Orm.Updates(param.DB)
	if param.DB.Threshold == 0 {
		db.Update("threshold", param.DB.Threshold)
	}
	if param.DB.PlaceId == 0 {
		db.Update("place_id", param.DB.PlaceId)
	}
	return dingo.ErrorIf(db.Error)
}

// 优惠券
func (d *CouponDao) InsertOrderCoupon(param *request.DbOrderCouponReq) *dingo.ErrorWrap {
	db := global.Orm.Create(&param.DB)
	return dingo.ErrorIf(db.Error)
}

func (d *CouponDao) GetOrderCouponByName(name string) *dingo.ErrorWrap {
	dbInfo := &coupon.OrderCoupon{}
	db := global.Orm.Table("order_coupon oc").Where("name=?", name)
	db.Order("id DESC").Find(&dbInfo)

	return dingo.ErrorIf(db.Error, dbInfo)
}

// 查询优惠券
func (d *CouponDao) GetOrderCoupon(param *request.GetCouponListReq) *dingo.ErrorWrap {
	var (
		lst    []*request.GetCouponListRes
		count  int64
		limit  int = param.PageSize
		offset int = param.PageSize * (param.PageNo - 1)
	)

	field := `oc.id,place_id,discounts,threshold,num,grant_num,type,order_type,oc.status,name,oc.project_label,
	p.place_name,message,DATE_FORMAT(start_time,'%Y-%m-%d %T')start_time,DATE_FORMAT(end_time,'%Y-%m-%d %T')
	end_time,DATE_FORMAT(create_time,'%Y-%m-%d %T')create_time,DATE_FORMAT(update_time,'%Y-%m-%d %T')update_time`
	db := global.Orm.Table("order_coupon oc").Select(field)
	db.Joins("LEFT JOIN places p ON oc.place_id=p.id")

	if param.IsAdmin != helper.TypeNumIsAdminOperator {
		db.Where("p.user_id=?", param.LoginUserId)
	}

	if param.Id > 0 {
		db.Where("oc.id=?", param.Id)
	}
	if param.Status > 0 {
		db.Where("oc.status=?", param.Status)
	}
	if param.PlaceId > 0 {
		db.Where("oc.place_id=?", param.PlaceId)
	}
	if param.Name != "" {
		db.Where("oc.name LIKE ?", "%"+param.Name+"%")
	}
	if param.IsValid {
		db.Where("oc.status=?", helper.TypeNumOrderCouponStatusNotUnderway)
		db.Where("oc.start_time<=now() AND oc.end_time>now()")
	}

	db.Order("oc.id desc")
	db.Limit(limit).Offset(offset).Find(&lst).Limit(-1).Offset(-1).Count(&count)

	return dingo.ErrorIf(db.Error, lst, count)
}

// UpdateStewardRoomCoupon 更新房间设备抵扣优惠
func (d *CouponDao) UpdateStewardRoomCoupon(settMoney int64, couponInfo *coupon.RoomCouponRecord) (int64, error) {
	amount := couponInfo.MaxAmount
	if settMoney < int64(amount) {
		amount = int(settMoney)
	}

	data := map[string]interface{}{
		"trade_no": couponInfo.TradeNo,
		"status":   1,
		"amount":   amount,
	}
	db := global.Orm.Table("room_coupon_record").Where("id=?", couponInfo.Id).Updates(&data)
	return int64(amount), db.Error
}

// GetTargetStewardRoomCoupon 创建房间设备抵扣优惠
func (d *CouponDao) GetTargetStewardRoomCoupon(params *orders.OrderModel) *coupon.RoomCouponRecord {
	data := &coupon.RoomCouponRecord{}
	endTime := time.Unix(int64(params.BeginAt), 0).Format("2006-01-02 15:04:05")

	db := global.Orm.Table("room_coupon_record").Where("status=?", 2)
	db.Where("place_id=? AND device_sn=? AND end_time>?", params.PlaceId, params.DeviceSn, endTime)

	db.Find(&data)
	data.TradeNo = params.TradeNo
	return data
}

// StewardGetRoomCoupon 创建房间设备抵扣优惠
func (d *CouponDao) StewardGetRoomCoupon(params *request.StewardAddRoomCouponReq) *dingo.ErrorWrap {
	data := &coupon.RoomCouponRecord{}
	h, _ := time.ParseDuration("12h")
	endTime := time.Now().Add(h).Format("2006-01-02 15:04:05")

	db := global.Orm.Table("room_coupon_record").Where("place_id=? AND device_sn=?", params.PlaceId, params.DeviceSn)
	db.Where("status=?", 2)

	if params.TimeOff == 1 {
		db.Where("end_time>?", endTime)
	}

	db.Find(&data)
	return dingo.ErrorIf(db.Error, data)
}

// StewardAddRoomCoupon 创建房间设备抵扣优惠
func (d *CouponDao) StewardAddRoomCoupon(params *request.StewardAddRoomCouponReq) *dingo.ErrorWrap {
	oldRoomCoupon := d.StewardGetRoomCoupon(params).Unwrap().(*coupon.RoomCouponRecord)

	if oldRoomCoupon.Id > 0 {
		return dingo.ErrorIf(nil, oldRoomCoupon.MaxAmount)
	}

	h, _ := time.ParseDuration("24h")
	endTime := time.Now().Add(h).Format("2006-01-02 15:04:05")
	data := map[string]interface{}{
		"trade_no":   "",
		"place_id":   params.PlaceId,
		"place_room": params.PlaceRoom,
		"device_sn":  params.DeviceSn,
		"status":     2,
		"max_amount": params.Amount,
		"amount":     0,
		"end_time":   endTime,
	}
	db := global.Orm.Table("room_coupon_record").Create(&data)
	return dingo.ErrorIf(db.Error, params.Amount)
}

//查询优惠券
func (d *CouponDao) GetCoupon(couponId int) *dingo.ErrorWrap {
	m := coupon.New()
	db := global.Orm.Raw("select * from coupon where id = ?", couponId).Find(&m)
	return dingo.ErrorIf(db.Error, m)
}

//查询优惠券
func (d *CouponDao) GetCouponByIdx(idx string) *dingo.ErrorWrap {
	m := coupon.New()
	db := global.Orm.Raw("select * from coupon where idx = ? and status = 2", idx).Find(&m)
	return dingo.ErrorIf(db.Error, m)
}

func (d *CouponDao) InsertCouponInfo(m *couponinfo.CouponInfo) *dingo.ErrorWrap {
	log.Println("优惠券领取：", m)
	//couponInfo := &couponinfo.CouponInfo{}
	//couponInfo.UserId = userId
	//couponInfo.CId = 1
	//couponInfo.StartTime = couponInfoModel.StartTime
	//couponInfo.EndTime = couponInfoModel.EndTime
	//couponInfo.Status = 1
	db := global.Orm.Debug().Table(m.TableName()).Create(&m)
	return dingo.ErrorIf(db.Error, true)
}

func (d *CouponDao) GetCouponInfo(userId int) (*dingo.ErrorWrap, int64) {
	m := couponinfo.New()
	db := global.Orm.Debug().Raw("select * from coupon_info where user_id = ? AND status = 1", userId).Find(&m)

	return dingo.ErrorIf(db.Error, m), db.RowsAffected
}

func (d *CouponDao) GetByOpenIdAndTradeNoCouponInfo(openId, tradeNo string) (*dingo.ErrorWrap, int64) {
	m := couponinfo.New()
	sql := `select * from coupon_info where open_id=? AND trade_no=? AND status=1`
	db := global.Orm.Debug().Raw(sql, openId, tradeNo).Find(&m)

	return dingo.ErrorIf(db.Error, m), db.RowsAffected
}

func (d *CouponDao) GetByOpenIdCouponInfo(openId string) (*dingo.ErrorWrap, int64) {
	m := couponinfo.New()
	db := global.Orm.Debug().Raw("select * from coupon_info where open_id = ? AND status = 1", openId).Find(&m)

	return dingo.ErrorIf(db.Error, m), db.RowsAffected
}

func (d *CouponDao) SetUnderCouponInfo(param *couponinfo.CouponInfo) *dingo.ErrorWrap {
	updateData := map[string]interface{}{}
	if param.TradeNo != "" {
		updateData["trade_no"] = param.TradeNo
	}

	db := global.Orm.Model(&couponinfo.CouponInfo{}).Where("id=? AND  status=?", param.Id, param.Status).Updates(updateData)
	return dingo.ErrorIf(db.Error)
}

func (d *CouponDao) GetCouponInfoLimit(userId int) *dingo.ErrorWrap {
	m := couponinfo.New()
	db := global.Orm.Debug().Raw("select * from coupon_info where user_id = ?  order by start_time desc limit 1", userId).Find(&m)
	return dingo.ErrorIf(db.Error, m)
}

func (d *CouponDao) GetCouponInfoStatus(openId string) (*dingo.ErrorWrap, int64) {
	var discounts int
	sql := `select c.discounts as discounts from coupon_info c_info LEFT JOIN coupon c ON c_info.c_id = c.id  
	where c_info.open_id = ? AND c_info.status = 1 AND c_info.order_coupon_record_id=0`
	db := global.Orm.Debug().Raw(sql, openId).Find(&discounts)
	return dingo.ErrorIf(db.Error, discounts), db.RowsAffected
}

func (d *CouponDao) GetCouponInfoOpenId(openId string) *dingo.ErrorWrap {
	m := couponinfo.New()
	db := global.Orm.Debug().Raw("select * from coupon_info where open_id = ? AND status = 1", openId).Find(&m)

	return dingo.ErrorIf(db.Error, m)
}

func (d *CouponDao) GetCouponInfoOpenIdAndTradeNo(openId, tradeNo string) *dingo.ErrorWrap {
	m := couponinfo.New()
	db := global.Orm.Debug().Raw("select * from coupon_info where open_id = ? AND trade_no=? AND status = 1", openId, tradeNo).Find(&m)

	return dingo.ErrorIf(db.Error, m)
}

//func (d *CouponDao) GetCountInfoByOpenId(openId string) *dingo.ErrorWrap {
//
//}

//优惠券编辑
func (d *CouponDao) CouponInfoEditDao(m *couponinfo.CouponInfo, orderMoney int) *dingo.ErrorWrap {

	if db := global.Orm.Table("coupon_info").Where("id = ?", m.Id).Updates(&m); db.Error != nil {
		return dingo.ErrorIf(db.Error, false)
	}

	if m.OrderCouponRecordId > 0 && m.Status == 2 {
		orderIndo := NewOrderDao().GetOrderDetailBytTradeNo(m.OrderId)
		updateData := map[string]interface{}{
			"status":           helper.TypeNumOrderCouponRecordStatusUse,
			"deduction_amount": orderIndo.CouponMoney,
			"trade_no":         m.OrderId,
		}
		if db := global.Orm.Table("order_coupon_record").Where("id=?", m.OrderCouponRecordId).Updates(updateData); db.Error != nil {
			return dingo.ErrorIf(db.Error, false)
		}
	}

	return dingo.ErrorIf(nil, true)
}

func (d *CouponDao) CouponInfoByOpenIdEditDao(openId string, m *couponinfo.CouponInfo) *dingo.ErrorWrap {
	log.Println("优惠券打印日志，openId:", openId, m)
	db := global.Orm.Debug().Table("coupon_info")
	db.Where("open_id = ?", openId)
	db.Model(&m)
	db.Updates(&m)
	if db.Error != nil {
		return dingo.ErrorIf(db.Error, false)
	}

	return dingo.ErrorIf(db.Error, true)
}

//根据会员类型Id获取优惠券
func (d *CouponDao) GetCouponInfoByMemberTypeId(memberTypeId, projectLabel string) *dingo.ErrorWrap {
	m := coupon.Coupon{}
	db := global.Orm.Debug().Table("coupon").
		Where("member_type_id = ?", memberTypeId).
		Where("project_label = ?", projectLabel).
		Find(&m)
	return dingo.ErrorIf(db.Error, m)
}
